﻿using Nature.Core.Config;
using Nature.Core.Exceptions;
using StructureMap;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Nature.Core.Cache
{
    public static class CacheManager
    {
        private static readonly IList<BaseCacheStrategy> _cacheStrategys = new List<BaseCacheStrategy>();

        private static readonly IList<string> _cacheGroupNames = new List<string>();

        private static bool _hasBooted;

        public static void Boot()
        {
            if (_hasBooted) return;

            var cacheConfig = ConfigManager.GetSection<ConfigCacheSection>(ConfigCacheSection.SectionName);

            ObjectFactory.Configure(c =>
            {
                foreach (ConfigCacheGroup config in cacheConfig.CacheGroups)
                {
                    c.For(typeof(BaseCacheStrategy))
                        .Singleton()
                        .Use(config.Type)
                        .CtorDependency<string>("cacheGroupName")
                        .Is(config.Name)
                        .CtorDependency<TimeSpan>("interval")
                        .Is(config.Interval)
                        .Name = config.Name;
                    _cacheGroupNames.Add(config.Name);
                }
            });

            foreach (string name in _cacheGroupNames)
            {
                _cacheStrategys.Add(ObjectFactory.GetNamedInstance<BaseCacheStrategy>(name));
            }

            _hasBooted = true;
        }

        private static void AddCacheStrategy(BaseCacheStrategy strategy)
        {
            if (_cacheStrategys.Where(w => w.CacheGroupName.Equals(strategy.CacheGroupName)).Count() > 0)
            {
                throw new FrameExcetpion("FCache1", new[] { strategy.CacheGroupName });
            }
            _cacheStrategys.Add(strategy);
        }

        public static bool Exist(string cacheGroupName)
        {
            if (_cacheStrategys.Count(c => c.CacheGroupName == cacheGroupName) > 0)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 如果不存在该缓存组，则创建
        /// </summary>
        /// <param name="cacheGroupName"></param>
        /// <param name="interval"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static BaseCacheStrategy AddCacheStrategyIfNotExist(string cacheGroupName, TimeSpan interval,
            Type type = null)
        {
            if (!Exist(cacheGroupName))
            {
                return AddCacheStrategy(cacheGroupName, interval, type);
            }
            return GetStrategy(cacheGroupName);
        }
        /// <summary>
        /// 创建缓存组，如果名字重复则抛出异常
        /// </summary>
        /// <param name="cacheGroupName"></param>
        /// <param name="interval"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static BaseCacheStrategy AddCacheStrategy(string cacheGroupName, TimeSpan interval, Type type = null)
        {
            //如果不传入实现类型，则使用默认类型实现
            if (type == null)
            {
                type = typeof(DefaultCacheStrategy);
            }

            if (_cacheStrategys.Count(c => c.CacheGroupName == cacheGroupName) > 0)
            {
                throw new FrameExcetpion("FCache1", new[] { cacheGroupName });
            }

            //配置反射
            ObjectFactory.Configure(
                c =>
                {
                    c.For(typeof(BaseCacheStrategy))
                        .Singleton()
                        .Use(type)
                        .CtorDependency<string>("cacheGroupName")
                        .Is(cacheGroupName)
                        .CtorDependency<TimeSpan>("interval")
                        .Is(interval)
                        .Name = cacheGroupName;
                });
            _cacheGroupNames.Add(cacheGroupName);
            //创建实例
            var strategy = ObjectFactory.GetNamedInstance<BaseCacheStrategy>(cacheGroupName);
            if (strategy == null)
            {
                throw new FrameExcetpion("FCache2", new[] { cacheGroupName });
            }
            _cacheStrategys.Add(strategy);

            return strategy;
        }

        public static BaseCacheStrategy GetStrategy(string cacheGroupName)
        {
            return ObjectFactory.GetNamedInstance<BaseCacheStrategy>(cacheGroupName);
        }
    }
}
